package com.gframework.autoconfigure.mvc;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;

import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.convert.converter.Converter;
import org.springframework.http.converter.HttpMessageConverter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.gframework.boot.mvc.controller.convert.CompatibleObjectMapper;
import com.gframework.boot.mvc.controller.convert.StringToDateConvert;
import com.gframework.boot.mvc.controller.convert.StringToLocalDateConvert;
import com.gframework.boot.mvc.controller.convert.StringToLocalDateTimeConvert;
import com.gframework.boot.mvc.controller.convert.TimestampUnifiedDateConverter;
import com.gframework.boot.mvc.controller.convert.UnifiedDateConverter;
import com.gframework.boot.mvc.controller.protocal.FileValueInterceptor;
import com.gframework.boot.mvc.controller.protocal.PageHelperValueInterceptor;
import com.gframework.boot.mvc.controller.protocal.RestResponseHandler;
import com.gframework.boot.mvc.controller.protocal.basic.BasicProtocalControllerAOP;
import com.gframework.boot.mvc.controller.protocal.basic.GFrameworkControllerAdvice;
import com.gframework.boot.mvc.controller.protocal.basic.GFrameworkErrorController;
import com.gframework.boot.mvc.controller.protocal.basic.ServerResponseRestHandler;
import com.gframework.boot.mvc.filter.CSRFSafeFilter;
import com.gframework.boot.mvc.filter.ClickHijackSafeFilter;
import com.gframework.boot.mvc.filter.CrossDomainAccessFilter;
import com.gframework.boot.mvc.filter.DefaultRestRedirectInterceptor;
import com.gframework.boot.mvc.filter.RestRequestHandleFilter;

/**
 * 统一mvc前后端rest接口响应结果/统一日期格式装配类
 * 
 * @since 1.0.0
 * @author Ghwolf
 * @see ErrorMvcAutoConfiguration
 */
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(MvcProperties.class)
@Import({ 
	FileValueInterceptor.class, PageHelperValueInterceptor.class,
	DefaultRestRedirectInterceptor.class,
	
	CSRFSafeFilter.class,
	ClickHijackSafeFilter.class,
	CrossDomainAccessFilter.class,
	RestRequestHandleFilter.class,
})
@AutoConfigureBefore(ErrorMvcAutoConfiguration.class)
public class UnifyRestFormatAutoConfiguration {

	/**
	 * 前后端统一rest格式核心处理类
	 */
	@Bean
	@ConditionalOnMissingBean(RestResponseHandler.class)
	public RestResponseHandler serverResponseRestHandler(MvcProperties properties) {
		return new ServerResponseRestHandler(properties);
	}
	
	/**
	 * 前后端统一rest格式核心AOP类
	 */
	@Bean
	public BasicProtocalControllerAOP gframeworkBasicProtocalControllerAOP(List<HttpMessageConverter<?>> converters) {
		return new BasicProtocalControllerAOP(converters);
	}

	/**
	 * 修改默认异常处理器
	 */
	@Bean
	public ErrorController gframeworkErrorController() {
		return new GFrameworkErrorController();
	}
	
	/**
	 * 修改默认异常处理器
	 */
	@Bean
	public GFrameworkControllerAdvice gframeworkControllerAdvice() {
		return new GFrameworkControllerAdvice();
	}
	
	/**
	 * 自定义mvc的ObjectMapper，对日期转换进行统一处理，并且对前后端通讯的部分细节问题进行处理，如long精度丢失等。
	 */
	@Bean
	public ObjectMapper gframeworkMvcObjectMapper() {
		return new CompatibleObjectMapper();
	}

	/**
	 * 同一日期转换抽象接口
	 */
	@Bean
	@ConditionalOnMissingBean
	public UnifiedDateConverter gframeworkDefaultUnifiedDateConverter(MvcProperties properties) {
		return new TimestampUnifiedDateConverter(properties);
	}

	@Bean
	public Converter<String, Date> gframeworkStringToDateConvert(UnifiedDateConverter converter) {
		return new StringToDateConvert(converter);
	}

	@Bean
	public Converter<String, LocalDate> gframeworkLocalDateToDateConvert(UnifiedDateConverter converter) {
		return new StringToLocalDateConvert(converter);
	}

	@Bean
	public Converter<String, LocalDateTime> gframeworkLocalDateTimeToDateConvert(UnifiedDateConverter converter) {
		return new StringToLocalDateTimeConvert(converter);
	}
}
